package jwts

import (
	"5title_gin/global"
	"5title_gin/pkg/utils/res"
	"5title_gin/pkg/utils/stringUtil"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"go.uber.org/zap"
	"strings"
	"time"
)

type Claims struct {
	UserID uint `json:"user_id"`
	RoleID uint `json:"role_id"`
}
type MyClaims struct {
	Claims
	jwt.RegisteredClaims
}

// GenerateToken 生成token
func GenerateToken(data Claims) (string, string, error) {
	AccessClaims := MyClaims{
		Claims: data,

		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(global.Config.Jwt.AccessExpire) * time.Hour)), //有效时间
			Issuer:    global.Config.Jwt.Issuer,                                                                      //签发人
		},
	}

	accessToken, _ := generateJWT(AccessClaims)
	RefreshClaims := MyClaims{
		Claims: data,

		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(global.Config.Jwt.RefreshExpire) * time.Hour)), //有效时间
			Issuer:    global.Config.Jwt.Issuer,                                                                       //签发人
		},
	}

	refreshToken, _ := generateJWT(RefreshClaims)
	return accessToken, refreshToken, nil
}

// CheckToken 验证token
func CheckToken(token string) (*MyClaims, error) {
	//解析、验证并返回token。
	tokenObj, err := jwt.ParseWithClaims(token, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(global.Config.Jwt.SecretKey), nil
	})

	if err != nil {
		zap.S().Errorf("验证jwt失败 %s", err)
		return nil, err
	}

	if claims, ok := tokenObj.Claims.(*MyClaims); ok && tokenObj.Valid {
		return claims, nil
	} else {
		return nil, errors.New("token无效")
	}

	// 判断token时效
}

// 生成 JWT
func generateJWT(claims MyClaims) (string, error) {
	//使用指定的加密方式和声明类型创建新令牌
	tokenStruct := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	//获得完整的、签名的令牌
	token, err := tokenStruct.SignedString([]byte(global.Config.Jwt.SecretKey))
	if err != nil {
		zap.S().Errorf("颁发jwt失败 %s", err)
		return "", err
	}
	return token, nil
}

// HashToken 计算 token 哈希（防止 Redis 过载）
func HashToken(token string) string {
	return stringUtil.HashString(token)
}

// GetClaimsFromToken 从请求头中提取并验证 Token，返回 Claims
func GetClaimsFromToken(c *gin.Context) (*MyClaims, error) {
	// 获取并验证 Authorization 头
	tokenString := c.GetHeader("Authorization")
	if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer ") {
		res.FailWithMsg("未提供有效的 Token", c)
		return nil, fmt.Errorf("no valid token provided")
	}
	tokenString = strings.TrimPrefix(tokenString, "Bearer ")

	// 解析 Token
	claims, err := CheckToken(tokenString)
	if err != nil {
		res.FailWithMsg("Token 无效或已过期", c)
		return nil, err
	}

	return claims, nil
}
